2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #ifndef __JUCER_POSITIONPROPERTYBASE_JUCEHEADER__
27 #define __JUCER_POSITIONPROPERTYBASE_JUCEHEADER__
29 #include "../ui/jucer_PaintRoutineEditor.h"
30 #include "../ui/jucer_ComponentLayoutEditor.h"
32 //==============================================================================
34 Base class for a property that edits the x, y, w, or h of a PositionedRectangle.
36 class PositionPropertyBase
: public PropertyComponent
,
37 protected ChangeListener
,
38 private ButtonListener
41 enum ComponentPositionDimension
49 PositionPropertyBase (Component
* component_
,
51 ComponentPositionDimension dimension_
,
52 const bool includeAnchorOptions_
,
53 const bool allowRelativeOptions_
,
54 ComponentLayout
* layout_
)
55 : PropertyComponent (name
),
57 component (component_
),
58 dimension (dimension_
),
59 includeAnchorOptions (includeAnchorOptions_
),
60 allowRelativeOptions (allowRelativeOptions_
)
62 addAndMakeVisible (button
= new TextButton ("mode"));
63 button
->addListener (this);
64 button
->setTriggeredOnMouseDown (true);
65 button
->setConnectedEdges (TextButton::ConnectedOnLeft
| TextButton::ConnectedOnRight
);
67 addAndMakeVisible (textEditor
= new PositionPropLabel (*this));
70 ~PositionPropertyBase()
75 const String
getText() const
77 RelativePositionedRectangle
rpr (getPosition());
78 PositionedRectangle
& p
= rpr
.rect
;
84 if (p
.getPositionModeX() == PositionedRectangle::proportionOfParentSize
)
85 s
<< valueToString (p
.getX() * 100.0) << '%';
87 s
<< valueToString (p
.getX());
91 if (p
.getPositionModeY() == PositionedRectangle::proportionOfParentSize
)
92 s
<< valueToString (p
.getY() * 100.0) << '%';
94 s
<< valueToString (p
.getY());
98 if (p
.getWidthMode() == PositionedRectangle::proportionalSize
)
99 s
<< valueToString (p
.getWidth() * 100.0) << '%';
101 s
<< valueToString (p
.getWidth());
104 case componentHeight
:
105 if (p
.getHeightMode() == PositionedRectangle::proportionalSize
)
106 s
<< valueToString (p
.getHeight() * 100.0) << '%';
108 s
<< valueToString (p
.getHeight());
119 static const String
valueToString (const double n
)
121 return String (roundToInt (n
* 1000.0) / 1000.0);
124 void setText (const String
& newText
)
126 RelativePositionedRectangle
rpr (getPosition());
127 PositionedRectangle
p (rpr
.rect
);
128 const double value
= newText
.getDoubleValue();
133 if (p
.getPositionModeX() == PositionedRectangle::proportionOfParentSize
)
134 p
.setX (value
/ 100.0);
140 if (p
.getPositionModeY() == PositionedRectangle::proportionOfParentSize
)
141 p
.setY (value
/ 100.0);
147 if (p
.getWidthMode() == PositionedRectangle::proportionalSize
)
148 p
.setWidth (value
/ 100.0);
153 case componentHeight
:
154 if (p
.getHeightMode() == PositionedRectangle::proportionalSize
)
155 p
.setHeight (value
/ 100.0);
172 void changeListenerCallback (ChangeBroadcaster
*)
177 void showMenu (ComponentLayout
* layout
)
179 RelativePositionedRectangle
rpr (getPosition());
180 PositionedRectangle
p (rpr
.rect
);
182 PositionedRectangle::AnchorPoint xAnchor
= p
.getAnchorPointX();
183 PositionedRectangle::AnchorPoint yAnchor
= p
.getAnchorPointY();
184 PositionedRectangle::PositionMode xMode
= p
.getPositionModeX();
185 PositionedRectangle::PositionMode yMode
= p
.getPositionModeY();
186 PositionedRectangle::SizeMode sizeW
= p
.getWidthMode();
187 PositionedRectangle::SizeMode sizeH
= p
.getHeightMode();
189 String
relCompName ("parent");
191 Component
* const relComp
= layout
!= 0 ? layout
->getComponentRelativePosTarget (component
, (int) dimension
) : 0;
194 relCompName
= layout
->getComponentMemberVariableName (relComp
);
196 jassert (relCompName
.isNotEmpty());
200 if (dimension
== componentX
|| dimension
== componentY
)
202 const PositionedRectangle::PositionMode posMode
= (dimension
== componentX
) ? xMode
: yMode
;
204 m
.addItem (10, ((dimension
== componentX
) ? "Absolute distance from left of "
205 : "Absolute distance from top of ") + relCompName
,
206 true, posMode
== PositionedRectangle::absoluteFromParentTopLeft
);
208 m
.addItem (11, ((dimension
== componentX
) ? "Absolute distance from right of "
209 : "Absolute distance from bottom of ") + relCompName
,
210 true, posMode
== PositionedRectangle::absoluteFromParentBottomRight
);
212 m
.addItem (12, "Absolute distance from centre of " + relCompName
,
213 true, posMode
== PositionedRectangle::absoluteFromParentCentre
);
215 m
.addItem (13, ((dimension
== componentX
) ? "Percentage of width of "
216 : "Percentage of height of ") + relCompName
,
217 true, posMode
== PositionedRectangle::proportionOfParentSize
);
221 if (includeAnchorOptions
)
223 const PositionedRectangle::AnchorPoint anchor
= (dimension
== componentX
) ? xAnchor
: yAnchor
;
225 m
.addItem (14, (dimension
== componentX
) ? "Anchored at left of component"
226 : "Anchored at top of component",
227 true, anchor
== PositionedRectangle::anchorAtLeftOrTop
);
229 m
.addItem (15, "Anchored at centre of component", true, anchor
== PositionedRectangle::anchorAtCentre
);
231 m
.addItem (16, (dimension
== componentX
) ? "Anchored at right of component"
232 : "Anchored at bottom of component",
233 true, anchor
== PositionedRectangle::anchorAtRightOrBottom
);
238 const PositionedRectangle::SizeMode sizeMode
= (dimension
== componentWidth
) ? sizeW
: sizeH
;
240 m
.addItem (20, (dimension
== componentWidth
) ? "Absolute width"
242 true, sizeMode
== PositionedRectangle::absoluteSize
);
244 m
.addItem (21, ((dimension
== componentWidth
) ? "Percentage of width of "
245 : "Percentage of height of ") + relCompName
,
246 true, sizeMode
== PositionedRectangle::proportionalSize
);
248 m
.addItem (22, ((dimension
== componentWidth
) ? "Subtracted from width of "
249 : "Subtracted from height of ") + relCompName
,
250 true, sizeMode
== PositionedRectangle::parentSizeMinusAbsolute
);
254 if (allowRelativeOptions
&& layout
!= 0)
257 m
.addSubMenu ("Relative to", layout
->getRelativeTargetMenu (component
, (int) dimension
));
260 const int menuResult
= m
.showAt (button
);
264 if (dimension
== componentX
)
265 xMode
= PositionedRectangle::absoluteFromParentTopLeft
;
267 yMode
= PositionedRectangle::absoluteFromParentTopLeft
;
271 if (dimension
== componentX
)
272 xMode
= PositionedRectangle::absoluteFromParentBottomRight
;
274 yMode
= PositionedRectangle::absoluteFromParentBottomRight
;
278 if (dimension
== componentX
)
279 xMode
= PositionedRectangle::absoluteFromParentCentre
;
281 yMode
= PositionedRectangle::absoluteFromParentCentre
;
285 if (dimension
== componentX
)
286 xMode
= PositionedRectangle::proportionOfParentSize
;
288 yMode
= PositionedRectangle::proportionOfParentSize
;
292 if (dimension
== componentX
)
293 xAnchor
= PositionedRectangle::anchorAtLeftOrTop
;
295 yAnchor
= PositionedRectangle::anchorAtLeftOrTop
;
299 if (dimension
== componentX
)
300 xAnchor
= PositionedRectangle::anchorAtCentre
;
302 yAnchor
= PositionedRectangle::anchorAtCentre
;
306 if (dimension
== componentX
)
307 xAnchor
= PositionedRectangle::anchorAtRightOrBottom
;
309 yAnchor
= PositionedRectangle::anchorAtRightOrBottom
;
313 if (dimension
== componentWidth
)
314 sizeW
= PositionedRectangle::absoluteSize
;
316 sizeH
= PositionedRectangle::absoluteSize
;
321 if (dimension
== componentWidth
)
322 sizeW
= PositionedRectangle::proportionalSize
;
324 sizeH
= PositionedRectangle::proportionalSize
;
329 if (dimension
== componentWidth
)
330 sizeW
= PositionedRectangle::parentSizeMinusAbsolute
;
332 sizeH
= PositionedRectangle::parentSizeMinusAbsolute
;
337 if (allowRelativeOptions
&& layout
!= 0)
338 layout
->processRelativeTargetMenuResult (component
, (int) dimension
, menuResult
);
343 Rectangle
<int> parentArea
;
345 if (component
->findParentComponentOfClass ((ComponentLayoutEditor
*) 0) != 0)
347 parentArea
.setSize (component
->getParentWidth(), component
->getParentHeight());
349 else if (dynamic_cast <PaintRoutineEditor
*> (component
->getParentComponent()) != 0)
351 parentArea
= dynamic_cast <PaintRoutineEditor
*> (component
->getParentComponent())->getComponentArea();
358 int x
, xw
, y
, yh
, w
, h
;
359 rpr
.getRelativeTargetBounds (parentArea
, layout
, x
, xw
, y
, yh
, w
, h
);
361 PositionedRectangle
xyRect (p
);
362 PositionedRectangle
whRect (p
);
364 xyRect
.setModes (xAnchor
, xMode
, yAnchor
, yMode
, sizeW
, sizeH
,
365 Rectangle
<int> (x
, y
, xw
, yh
));
367 whRect
.setModes (xAnchor
, xMode
, yAnchor
, yMode
, sizeW
, sizeH
,
368 Rectangle
<int> (x
, y
, w
, h
));
370 p
.setModes (xAnchor
, xMode
, yAnchor
, yMode
, sizeW
, sizeH
,
371 Rectangle
<int> (x
, y
, xw
, yh
));
373 p
.setX (xyRect
.getX());
374 p
.setY (xyRect
.getY());
375 p
.setWidth (whRect
.getWidth());
376 p
.setHeight (whRect
.getHeight());
387 const Rectangle
<int> r (getLookAndFeel().getPropertyComponentContentPosition (*this));
389 button
->changeWidthToFitText (r
.getHeight());
390 button
->setTopRightPosition (r
.getRight(), r
.getY());
392 textEditor
->setBounds (r
.getX(), r
.getY(), button
->getX() - r
.getX(), r
.getHeight());
397 textEditor
->setText (getText(), false);
400 void buttonClicked (Button
*)
403 refresh(); // (to clear the text editor if it's got focus)
408 const String
newText (textEditor
->getText());
409 if (getText() != newText
)
413 //==============================================================================
414 virtual void setPosition (const RelativePositionedRectangle
& newPos
) = 0;
416 virtual const RelativePositionedRectangle
getPosition() const = 0;
419 class PositionPropLabel
: public Label
421 PositionPropertyBase
& owner
;
426 PositionPropLabel (PositionPropertyBase
& owner_
)
427 : Label (String::empty
, String::empty
),
430 setEditable (true, true, false);
432 setColour (backgroundColourId
, Colours::white
);
433 setColour (textColourId
, Colours::black
);
434 setColour (outlineColourId
, findColour (ComboBox::outlineColourId
));
436 setColour (TextEditor::textColourId
, Colours::black
);
437 setColour (TextEditor::backgroundColourId
, Colours::white
);
438 setColour (TextEditor::outlineColourId
, findColour (ComboBox::outlineColourId
));
445 TextEditor
* createEditorComponent()
447 TextEditor
* textEditor
= Label::createEditorComponent();
448 textEditor
->setInputRestrictions (14, "0123456789.-%");
455 owner
.textWasEdited();
459 ComponentLayout
* layout
;
460 PositionPropLabel
* textEditor
;
463 Component
* component
;
464 ComponentPositionDimension dimension
;
465 const bool includeAnchorOptions
, allowRelativeOptions
;
469 #endif // __JUCER_POSITIONPROPERTYBASE_JUCEHEADER__